package com.boot.web.log;

import com.boot.core.thread.ThreadLocalHelper;
import com.boot.web.exception.GlobalException;
import com.boot.web.http.Status;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

/**
 * @author 霜寒 <1621856595@qq.com>
 * @description 统一日志处理
 * @date 2019/8/21 16:03
 **/

@Aspect
@Slf4j
@Component
@EnableAspectJAutoProxy
public class LogAspect {

    @Autowired
    ObjectMapper mapper;

    @Pointcut("bean(*Controller)|| @annotation(Log4http)")
    public void webLog() {
    }

    /**
     * @author 霜寒 <1621856595@qq.com>
     * @description 在切点之前织入
     * @date 2019/8/21 16:12
     **/
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request;
        if (attributes != null) {
            request = attributes.getRequest();
        } else {
            throw new GlobalException(Status.NO_REQUEST, HttpStatus.INTERNAL_SERVER_ERROR);
        }
        // 打印请求相关参数
        log.debug("========================================== Start ===========================================");
        // 打印调用 controller 的全路径以及执行方法
        log.debug("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印请求 url
        log.debug("URL            : {}", request.getRequestURL().toString());
        // 打印 Http method
        log.debug("HTTP Method    : {}", request.getMethod());
        // 打印请求的 IP
        log.debug("IP             : {}", request.getRemoteAddr());
        // 打印请求头
        log.debug("Request Headers:");
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            log.debug("               : {} = {}", headerName, request.getHeader(headerName));
        }
        try {
            // 打印 Cookies
            log.debug("Request Cookies: {}", mapper.writeValueAsString(request.getCookies()));
            // 打印请求入参
            log.debug("Request Args   : {}", mapper.writeValueAsString(joinPoint.getArgs()));
        } catch (JsonProcessingException ignore) {
            //            log.warn("printStackTrace: {}", "无法转化请求体");
        }
    }

    /**
     * @author 霜寒 <1621856595@qq.com>
     * @description 在切点之后织入
     * @date 2019/8/21 16:16
     **/
    @After("webLog()")
    public void doAfter() {
        ThreadLocalHelper.clear();
        log.debug("=========================================== End ============================================");
        // 每个请求之间空一行
        //        log.debug("");
    }

    /**
     * @author 霜寒 <1621856595@qq.com>
     * @description 打印响应和时间
     * @date 2019/8/21 16:17
     **/
    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        try {
            // 打印出参
            log.debug("Response Args  : {}", mapper.writeValueAsString(result));
        } catch (JsonProcessingException ignore) {
            log.warn("printStackTrace: {}", "无法转化响应");
        }
        // 执行耗时
        log.debug("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
        return result;
    }

}
